use core::base_node::{NodeData, BaseNode, TBaseNode};
use core::blackboard::Blackboard;
use std::collections::HashMap;
use uuid::Uuid;
use core::tick::Tick;

pub struct NodeTypeRegister {
    container: Box<HashMap<String, Box<FnMut(serde_json::Value, &mut HashMap<String, Box<TBaseNode>>)>>>
}

impl NodeTypeRegister {
    pub fn new () -> NodeTypeRegister {
        NodeTypeRegister {
            container: Box::new(HashMap::new())
        }
    }
    pub fn register_type(&mut self, name: String, creator: Box<FnMut(serde_json::Value, &mut HashMap<String, Box<TBaseNode>>)>) -> bool {
        if self.container.contains_key(&name) {
            return false;
        }
        self.container.insert(name, creator);
        return true;
    }

    pub fn create_node(&mut self, type_name: &String, config: serde_json::Value, nodes: &mut HashMap<String, Box<TBaseNode>>) {
        match self.container.get_mut(type_name) {
            Some(_creator) => {
                _creator(config, nodes);
            }
            None => {
                println!("create_node not exist {:?}", type_name);
            }
        };
    }


}


#[derive(Debug, Deserialize, PartialEq)]
pub struct BehaviorTreeConfig {
    id: String,
    // name: String,
    title: String,
    description: String,
    properties: HashMap<String, serde_json::Value>,
    // debug: bool,
    nodes: HashMap<String, serde_json::Value>,
    root: String,
}

pub struct BehaviorTree {
    pub id: String,
    name: String,
    title: String,
    description: String,
    properties: HashMap<String, serde_json::Value>,
    debug: bool,
    // nodes: HashMap<String, Box<TBaseNode>>,
    // blackboard: Blackboard
}

impl BehaviorTree {
    // json, node register
    pub fn load(data: serde_json::Value, container: &mut NodeTypeRegister) -> Result<(BehaviorTree, Box<TBaseNode>), String> {
        let bt_config: BehaviorTreeConfig = match serde_json::from_value(data) {
            Ok(_t) => {
                _t
            }
            Err(_e) => {
                return Err(_e.to_string());
            }
        };

        let mut bt = BehaviorTree {
            id: bt_config.id,
            name: "bt_config.name".to_string(),
            title: bt_config.title,
            description: bt_config.description,
            properties: bt_config.properties,
            debug: false,
            // nodes: HashMap::new(),
            // root: None,
            // blackboard: Blackboard::new()
        };

        let mut nodes = HashMap::new();
        for (id, config) in bt_config.nodes.iter() {
            match config.get("name") {
                Some(_n) => {
                    match _n.as_str() {
                        Some(_s) => {
                            container.create_node(&_s.to_string(), config.clone(), &mut nodes);
                        }
                        None => {
                            println!("1111111");
                            continue
                        }
                    }
                }
                None => {
                    println!("22222");
                    continue;
                }
            };
        }
        println!("{:?}  {:?}", &bt_config.root, nodes.len());
        let root = match nodes.remove(&bt_config.root) {
            Some(_n) => {
                let mut _n: Box<TBaseNode> = _n;
                BehaviorTree::trace_node_children(&mut _n, &mut nodes);
                _n
            }
            None => {
                return Err("not root".to_string())
            }
        };

        Ok((bt, root))
    }

    pub fn trace_node_children(parent: &mut Box<TBaseNode>, nodes: &mut HashMap<String, Box<TBaseNode>>) {
        match &parent.get_base_node_ref().nodes {
            Some(_nodes) => {
                for (id,child_node_info) in _nodes.iter() {
                    match nodes.remove(id) {
                        Some(mut _n) => {
                            BehaviorTree::trace_node_children(&mut _n, nodes);
                            parent.add_child(_n);
                        }
                        None => {
                            println!("trace_node_children none");
                        }
                    };
                }
            }
            None => {

            }
        }
        match &parent.get_base_node_ref().children {
            Some(_children) => {
                for id in _children.iter() {
                    match nodes.remove(id) {
                        Some(mut _n) => {
                            BehaviorTree::trace_node_children(&mut _n, nodes);
                            println!("add_child ");
                            parent.add_child(_n);
                        }
                        None => {
                            println!("trace_node_children none node children {:?} {:?} {:?}", parent.get_base_node_ref().name, id, _children.len());
                        }
                    };
                }
            }
            None => {
                // println!("trace_node_children none children {:?}", parent.get_base_node_ref().name);
            }
        }
        match &parent.get_base_node_ref().child {
            Some(_child) => {
                match nodes.remove(_child) {
                    Some(mut _n) => {
                        BehaviorTree::trace_node_children(&mut _n, nodes);
                        parent.add_child(_n);
                    }
                    None => {
                        println!("trace_node_children none node child {:?}", parent.get_base_node_ref().name);
                    }
                };
            }
            None => {
                // println!("trace_node_children none  child {:?}", parent.get_base_node_ref().name);
            }
        }
    }

    // pub fn tick( &mut self, root: &mut Box<TBaseNode>) {
    //     let mut tick = Tick {
    //         tree: self,
    //         blackboard: Blackboard::new(),
    //         node_count: 0,
    //         open_nodes: Vec::new()
    //     };
    //     root.execute(&mut tick);
    // }
}